/**********************************************************************************************/
/* FBL_ArraySet.h																			  */
/*                                                                       					  */
/* Copyright Paradigma, 1993-2006                                       					  */
/* All Rights Reserved.                                                 					  */
/**********************************************************************************************/

#ifndef _FBL_ArraySet_h 
	#define _FBL_ArraySet_h
#pragma once

#include <VShared/FBL/publ/Sets/FBL_Set.h>
#include <VShared/FBL/publ/Headers/FBL_pre_header.h>

#undef new

#include <memory>

#if DEBUG_NEW
#define new NEW
#endif // DEBUG_NEW


/**********************************************************************************************/
FBL_Begin_Namespace


/**********************************************************************************************/
SMART_CLASS( BitSet );
SMART_CLASS( ArraySet );
SMART_CLASS( SetIterator );


/**********************************************************************************************/
/*
	General purpose class.
	Implement Set of ulong numbers as array.	
	Can contain up to MAX_ULONG items.
	Array can change its size in both directions.
*/

class FBL_SHARED_EXP_CLASS ArraySet : public Set
{ 	
		friend class ArraySetIterator;

    public://///////////////////////////////////////////////////////////////////////////////////

							ArraySet( ulong ioLimitCount );
							
							ArraySet( const ArraySet& inSet );
							
							// You can set ioLimitCount e.g. to 10, 
							// then only 10 first items will be copied into ArraySet.
							ArraySet( const BitSet& inSet, ulong ioLimitCount = ULONG_MAX );
							
virtual			  			~ArraySet( void );


    public://///////////////////////////////////////////////////////////////////////////////////

// Set API:
		
	//----------------------
	// Properties:

virtual ulong				get_Count( void ) const;

virtual bool				get_IsEmpty( void ) const throw() 
								{ return bool( pFinish == pStart ); } 

virtual SetIterator_Ptr		get_Iterator( void ) const;

virtual	bool				get_IsSorted( void ) const throw();
virtual	void				put_IsSorted( bool inSorted ) throw();


	// ---------------------
	// Item methods:

							/// ATTENTION: it just append items to array. It not check that 
							/// item already exists. This works for now. 	
virtual	void				Append( ID_TYPE inItem );

							/// Find in array item and remove it.
							/// Back items moves forward.
virtual	void				Remove( ID_TYPE inItem );	

virtual	bool				Include( ID_TYPE inItem ) const;


	// ---------------------

virtual Set*				Clone( bool inCopy = true ) const throw();


	// ---------------------
	// Sorting Methods:
				
							/// Sort items by values.
virtual	void				Sort( void ) throw();
							
	//----------------------
	// Unary operators:

virtual Set_Ptr				Union 		 		( const Set_Ptr inSet ); // OR
virtual Set_Ptr				Intersection		( const Set_Ptr inSet ); // AND
virtual Set_Ptr				Difference   		( const Set_Ptr inSet ); // AND NOT
virtual Set_Ptr				SymmetricDifference	( const Set_Ptr inSet ); // XOR

	
	public://///////////////////////////////////////////////////////////////////////////////////

// I_Serializable API:

virtual void				From( I_IStream_Ptr inStream,
								  bool inBlock = true );

virtual void				From( I_PacketRcv*	 	inPacket,
								  bool 				inBlock = true );


virtual void				To( I_OStream_Ptr inStream,
								bool inBlock = true ) const;


virtual void				To( I_PacketSnd*		inPacket,
								bool 				inBlock = true ) const;


    public://///////////////////////////////////////////////////////////////////////////////////

// ArraySet API:

	//-----------------
	// Properties:

		ulong				get_MaxCount( void ) const;
		ulong				get_Size( void ) const
								{ return ulong((pStorageEnd - pStart) * sizeof(ID_TYPE)); }

							/// Returns reference on item at the specified position.
		ID_TYPE&	 		operator()( ulong inPos ) const;
							

		// Sets operations: 
		// Note: for much better performance use BitSet methods (if your task allows this).

		ArraySet_Ptr		Intersection 		( ArraySet_Ptr inArraySet ) throw(); // AND
		ArraySet_Ptr		Union		 		( ArraySet_Ptr inArraySet ) throw(); // OR
		ArraySet_Ptr		Difference			( ArraySet_Ptr inArraySet ) throw(); // AND NOT
		ArraySet_Ptr		SymmetricDifference	( ArraySet_Ptr inArraySet ) throw(); // XOR
		
							// This method is dispatcher between above 4 Set Operations. 
static ArraySet_Ptr			MakeOperation( 		
								ArraySet_Ptr 	inLeftSet, 
								SetOperation	inOperation,
								ArraySet_Ptr 	inRightSet ) throw();						

	// ---------------------
	// Item Methodes:
	
							/// Append several items at once.
		void 				AppendItems( ID_TYPE* pArray, ulong Count );

							/// Append several items in reverse order at once.
		void 				AppendItemsReverse( ID_TYPE* pArray, ulong Count );

							/// Insert item to the specified position.
							/// Next items moved back. 
		void				InsertItem( ulong inPos, ID_TYPE inItem );	
		
							/// Remove item at specified position, 0..
							/// Next items is moved forward.
		void				RemoveAt( ulong inPos, ulong inCount = 1 );
		
							/// Returns index (1..) of given inItem in set.
							/// Returns 0 if not found.
		ulong	 			FindIndex( ID_TYPE inItem, ulong inFrom = 0 , ulong inTo = 0 );

							
	public://///////////////////////////////////////////////////////////////////////////////////
 
		/* advanced methods: */

		ID_TYPE*			begin( void ) const;	///< to have direct access.
		ID_TYPE*			end( void ) const;		///< to have direct access.
 
							/// If array was changed directly throw pointers (for speed) 
							/// then you must set right position of pFinish marker.
		void 				SetItemsCount( ID_TYPE inNewCount );

							/// Can as grow, so and reduse size of set.Can truncate exisitng data.
			 				/// If NewItemsCount is 0 then free memory.
		void				Resize( ulong NewItemsCount );

							/// Check space before adding new data.
							/// If there is no more space, resize array, but
							/// not more than inMaxPossible.
		void				Tune( ulong inMaxPossible );


	protected://////////////////////////////////////////////////////////////////////////////////

		void				InitSelf( ID_TYPE ioLimitCount );


    protected://////////////////////////////////////////////////////////////////////////////////

		ID_TYPE*			pStart;			///< points to the first item.
		ID_TYPE*			pFinish;		///< points AFTER the last item.
		ID_TYPE*			pStorageEnd;	

		bool				isSorted;
};


/**********************************************************************************************/
struct I_OStream;
struct I_IStream;


/**********************************************************************************************/
I_IStream& operator>>( I_IStream& inStream, ArraySet*& outSet );
I_OStream& operator<<( I_OStream& inStream, const ArraySet* inSet );


/**********************************************************************************************/
inline ulong ArraySet::get_MaxCount( void ) const	
{ 
	return (ulong)(pStorageEnd - pStart); 
}

/**********************************************************************************************/
inline ulong ArraySet::get_Count( void ) const		
{ 
	return (ulong)(pFinish - pStart);		
}	

/**********************************************************************************************/
inline bool ArraySet::get_IsSorted( void ) const throw()		
{ 
	return isSorted; 				
}

/**********************************************************************************************/
inline void ArraySet::put_IsSorted( bool inSorted ) throw()	
{ 
	isSorted = inSorted; 			
}
		
/**********************************************************************************************/
inline ID_TYPE* ArraySet::begin( void ) const	
{ 
	return pStart;	
}	

/**********************************************************************************************/
inline ID_TYPE* ArraySet::end( void ) const	
{ 
	return pFinish;	
}	


/**********************************************************************************************/
inline void ArraySet::Append( ID_TYPE inItem )
{
	if( pFinish >= pStorageEnd )	// there is no place, reallocate.
	{
		// first time we allocate 100 items, then we double the size of the array.
		ID_TYPE NewSize = (pStorageEnd - pStart) ? (ulong) 2 * (pStorageEnd - pStart) : (ulong)100;
		Resize( NewSize ); 
	}
	
	*pFinish++ = inItem;
	isSorted = false;
	
}


/**********************************************************************************************/
inline ID_TYPE& ArraySet::operator()( ulong inIndex ) const
{
	FBL_CHECK( inIndex >= 1 ); 			// range 1..
	FBL_CHECK( inIndex <= get_Count() ); 	

	return *(pStart + inIndex - 1L);
	
}


/**********************************************************************************************/
FBL_End_Namespace


/**********************************************************************************************/
#include <VShared/FBL/publ/Headers/FBL_post_header.h>


#endif // _FBL_ArraySet_h

